package cn.lg.soar.system.biz.filetemplate;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.FileTypeUtils;
import cn.lg.soar.system.api.enums.AccessModeEnum;
import cn.lg.soar.system.api.enums.UploadModeEnum;
import cn.lg.soar.system.biz.filetemplate.model.PartInfoVO;
import cn.lg.soar.system.biz.modules.general.entity.FileStorage;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import lombok.SneakyThrows;

import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/3/1 17:25
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class AmazonS3FileTemplateImpl implements FileTemplate {

    private final AmazonS3 amazonS3;
    private final int configVersion;
    private final String bucketName;

    public AmazonS3FileTemplateImpl(FileStorage storage) {
        this.configVersion = storage.getVersion();
        this.bucketName = storage.getBucketName();
        String endpoint = storage.getEndpoint();
        String accessKey = storage.getAccessKey();
        String secretKey = storage.getSecretKey();
        // url以及region配置
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
                endpoint,
                storage.getRegion()
        );
        ClientConfiguration clientConfig = new ClientConfiguration();
        clientConfig.setProtocol(Protocol.HTTPS);

        AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);

        // 创建S3客户端
        amazonS3 = AmazonS3Client.builder()
                .withEndpointConfiguration(endpointConfiguration)
                .withClientConfiguration(clientConfig)
                .withCredentials(awsCredentialsProvider)
                .disableChunkedEncoding()
                .withPathStyleAccessEnabled(storage.getPathStyleAccess())
                .withForceGlobalBucketAccessEnabled(true)
                .build();
    }

    @Override
    public void upload(String filename, InputStream stream) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(FileTypeUtils.getContentType(filename));
        amazonS3.putObject(bucketName, filename, stream, objectMetadata);
    }

    @Override
    public InputStream getInputStream(String filename) {
        return amazonS3.getObject(bucketName, filename).getObjectContent();
    }

    @Override
    @SneakyThrows
    public S3Object getObject(String filename) {
        return amazonS3.getObject(bucketName, filename);
    }

    @Override
    public void deleteFile(String filename) {
        amazonS3.deleteObject(bucketName, filename);
    }

    @Override
    public boolean isExist(String filename) {
        try {
            amazonS3.getObjectMetadata(bucketName, filename);
        } catch (RuntimeException ignored) {
            return false;
        }
        return true;
    }

    @Override
    public URL getUrl(String filename) {
        return amazonS3.getUrl(bucketName, filename);
    }

    @Override
    public URL getAccessUrl(String filename, Date date) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, filename, HttpMethod.GET);
        request.setExpiration(date);
        return amazonS3.generatePresignedUrl(request);
    }

    @Override
    public String getUploadUrl(String filename) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, filename)
                .withMethod(HttpMethod.PUT)
                .withExpiration(new Date(System.currentTimeMillis() + 12 * 3600_000));
        return amazonS3.generatePresignedUrl(request).toString();
    }

    @Override
    public String getUploadUrl(String filename, String uploadId, Integer partNumber) {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, filename)
                .withMethod(HttpMethod.PUT)
                .withExpiration(new Date(System.currentTimeMillis() + 3600_000));
        request.addRequestParameter("partNumber", partNumber.toString());
        request.addRequestParameter("uploadId", uploadId);
        return amazonS3.generatePresignedUrl(request).toString();
    }

    @Override
    public String uploadInit(String filename) {
        InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, filename);
        InitiateMultipartUploadResult initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(initiateMultipartUploadRequest);
        return initiateMultipartUploadResult.getUploadId();
    }

    @Override
    public void uploadComplete(String filename, String uploadId, List<PartInfoVO> parts) {
        List<PartETag> eTags = parts.stream()
                .map(x -> new PartETag(x.getPartNumber(), x.getEtag()))
                .collect(Collectors.toList());
        CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest();
        completeMultipartUploadRequest.setKey(filename);
        completeMultipartUploadRequest.setUploadId(uploadId);
        completeMultipartUploadRequest.setPartETags(eTags);
        completeMultipartUploadRequest.setBucketName(bucketName);
        amazonS3.completeMultipartUpload(completeMultipartUploadRequest);
    }

    @Override
    public void uploadAbort(String filename, String uploadId) {
        AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest(bucketName, filename, uploadId);
        amazonS3.abortMultipartUpload(abortMultipartUploadRequest);
    }

    @Override
    public int getConfigVersion() {
        return configVersion;
    }

    @Override
    public void test() {
        amazonS3.listBuckets();
        AssertUtil.isTrue(amazonS3.doesBucketExistV2(bucketName), "目标桶不存在");
    }

}